fix(toolkit-lib): clean up the diff change set when early validation fails - #1821
Conversation
…fails When a diff change set fails early validation (for example a resource that already exists), `waitAndThrowOnProblem` threw before the change-set and empty-stack cleanup ran, orphaning the change set and leaving a new stack stuck in REVIEW_IN_PROGRESS, which then blocked subsequent change-set creation on that stack. Run the cleanup on the failure path too (best-effort, without masking the original error) so a failed diff no longer leaks the change set or the empty review stack. Fixes aws#1767
ShadowCat567
left a comment
There was a problem hiding this comment.
Hello @lemon0333! Thanks for the PR :D it looks good overall! I just have a few comments that can help improve it
| }); | ||
| } catch (e) { | ||
| // Best-effort cleanup so a failed change set doesn't leak; don't let a | ||
| // cleanup failure mask the original creation/validation error. |
There was a problem hiding this comment.
Can you log the error we caught here? Currently the error that gets thrown will still not be visible to the user because it gets consumed here:
(the actual error is only revealed if you use the--debug flag)
| await cleanup(); | ||
| } catch (cleanupError) { | ||
| await ioHelper.defaults.debug(format('Failed to clean up change set after a creation error: %s', cleanupError)); | ||
| } |
There was a problem hiding this comment.
having this try/catch may be overly defensive, I am not necessarily against it but why are we expecting that deletion might fail?
Address review: warn-log the caught error so the reason a diff change set failed is visible without -v (createDiffChangeSet otherwise only logs it at debug before falling back to a template diff), and elevate the best-effort cleanup failure log to warn. Assert the failure is surfaced in the test.
|
Thanks for the review @ShadowCat567! Addressed both:
Also added a test assertion that the failure reason is surfaced. Full |
Head branch was pushed to by a user without write access
ShadowCat567
left a comment
There was a problem hiding this comment.
Hello @lemon0333! Put some more thought into the try/catches, let me know what you think of my proposal
| StackName: changeSet.StackId ?? options.stack.stackName, | ||
| ClientRequestToken: randomUUID(), | ||
| let createdChangeSet: ChangeSetReport; | ||
| try { |
There was a problem hiding this comment.
I spent some more time thinking about this, I think the cleanest way to do this might be using a try/catch/finally:
try {
return await new ChangeSetDescriber({...});
} catch (e) {
await io.Helper.defaults.warn(...); // print the error
throw e;
} finally { // ensures we always clean up whether we ran into an error or not
// do clean up, surface errors if any appear
}
this means we are not calling the cleanup function in 2 places (and we probably don't need it to begin with). Let me know what you think!
Per review: move cleanup into a finally block so it runs once (not in two places) whether or not the change set succeeds, warn-log the failure reason in catch, and drop the extra defensive try/catch around cleanup.
|
Nice, that's cleaner — done in the latest commit. Moved the cleanup into a |
ShadowCat567
left a comment
There was a problem hiding this comment.
Nice job @lemon0333!
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1821 +/- ##
==========================================
- Coverage 90.32% 90.27% -0.05%
==========================================
Files 80 80
Lines 12124 12124
Branches 1716 1714 -2
==========================================
- Hits 10951 10945 -6
- Misses 1139 1145 +6
Partials 34 34
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Fixes #1767
When a
cdk diffchange set fails early validation (e.g. a resource that already exists),createChangeSetAndCleanupintoolkit-lib'scfn-api.tsthrew fromwaitAndThrowOnProblembefore the change-set and empty-stack cleanup could run. That orphaned the change set and left a new stack stuck inREVIEW_IN_PROGRESS, which then blocked subsequent change-set creation and forced the user to delete it manually in the console.This change runs the cleanup on the failure path too — deleting the change set and, for a brand new stack, the empty review stack — as a best-effort step that does not mask the original validation error. Successful diffs are unchanged.
Verified with a new unit test in
diff.test.ts(change set fails validation →DeleteChangeSetandDeleteStackare called); the fulldiff.test.tssuite passes (22/22).Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license